package diff

import (
	"fmt"
	"io"
	"log/slog"

	"github.com/dustin/go-humanize"
	"github.com/jedib0t/go-pretty/v6/table"

	"github.com/Zxilly/go-size-analyzer/internal/utils"
)

func diffString(b Base) string {
	switch b.ChangeType {
	case changeTypeChange:
		sign := "+"
		if b.To < b.From {
			sign = ""
		}

		return sign + utils.PercentString(float64(b.To-b.From)/float64(b.From))
	case changeTypeAdd:
		return "+100%"
	case changeTypeRemove:
		return "-100%"
	default:
		panic("unreachable")
	}
}

func bytesWithIgnore(b int64) string {
	if b == 0 {
		return ""
	}
	return humanize.Bytes(uint64(b))
}

func signedBytesString(b int64) string {
	sign := "+"
	if b < 0 {
		sign = "-"
		b = -b
	}
	return sign + humanize.Bytes(uint64(b))
}

func text(r *diffResult, writer io.Writer) error {
	slog.Info("Printing text diff report")

	t := table.NewWriter()
	t.SetStyle(utils.GetTableStyle())

	t.SetTitle("Diff between %s and %s", r.OldName, r.NewName)
	t.AppendHeader(table.Row{"Percent", "Name", "Old Size", "New Size", "Diff"})

	for _, pkg := range r.Packages {
		name := pkg.Name
		if name == "" {
			name = "<autogenerated>"
		}

		t.AppendRow(table.Row{
			diffString(pkg.Base),
			name,
			bytesWithIgnore(pkg.From),
			bytesWithIgnore(pkg.To),
			signedBytesString(pkg.To - pkg.From),
		})
	}

	t.AppendSeparator()

	for _, section := range r.Sections {
		t.AppendRow(table.Row{
			diffString(section.Base),
			section.Name,
			bytesWithIgnore(section.From),
			bytesWithIgnore(section.To),
			signedBytesString(section.To - section.From),
		})
	}

	t.AppendFooter(table.Row{
		diffString(Base{
			From:       r.OldSize,
			To:         r.NewSize,
			ChangeType: changeTypeChange,
		}),
		fmt.Sprintf("%s\n%s", r.OldName, r.NewName),
		humanize.Bytes(uint64(r.OldSize)),
		humanize.Bytes(uint64(r.NewSize)),
		signedBytesString(r.NewSize - r.OldSize),
	})

	data := []byte(t.Render() + "\n")

	slog.Info("Diff report rendered")

	_, err := writer.Write(data)

	slog.Info("Diff report written")

	return err
}
